home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 2.toast / pc / sample code / sound / sndplaydoublebuffer / _source / snd.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-06-23  |  9.1 KB  |  253 lines

  1. /*
  2.     File:        SND.c
  3.  
  4.     Contains:    Routines demonstrating how to parse 'snd ' resource files.
  5.  
  6.     Written by: Mark Cookson    
  7.  
  8.     Copyright:    Copyright © 1996-1999 by Apple Computer, Inc., All Rights Reserved.
  9.  
  10.                 You may incorporate this Apple sample source code into your program(s) without
  11.                 restriction. This Apple sample source code has been provided "AS IS" and the
  12.                 responsibility for its operation is yours. You are not permitted to redistribute
  13.                 this Apple sample source code as "Apple sample source code" after having made
  14.                 changes. If you're going to re-distribute the source, we require that you make
  15.                 it clear in the source that the code was descended from Apple sample source
  16.                 code, but that you've made changes.
  17.  
  18.     Change History (most recent first):
  19.                 8/31/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
  20.                 
  21.  
  22. */
  23.  
  24. #include "SND.h"
  25. /*
  26.     There are lots of places for reading a resource to go wrong.  This is
  27.     why I currently have the paranoid error checking.
  28.  
  29.     This routine works like the other parse header routines, except that
  30.     since it doesn't do any Resource Manager calls, it expects the file
  31.     pointer to be positioned right at the first byte of the data of the
  32.     'snd ' resource.  This way the FSRead that reads the header will work.
  33.  
  34.     The length calculation could probably use some work, but that would
  35.     require modifying the read routines.  Right now we just fudge the length
  36.     so that we will read all of a resource.
  37. */
  38. /*-----------------------------------------------------------------------*/
  39.         OSErr    ASoundGetSNDHeader        (SoundInfoPtr theSoundInfo,
  40.                                         long *dataStart,
  41.                                         long *length)
  42. /*-----------------------------------------------------------------------*/
  43. {
  44.     SoundComponentData        sndInfo;
  45.     Ptr                        theSoundHeader    = nil;
  46.     unsigned long            numFrames        = 0,
  47.                             dataOffset        = 0;
  48.     long                    headerBytes        = kMaxSNDHeaderSize;
  49.     short                    resNum            = 0;
  50.     OSErr                    theErr            = noErr;
  51.  
  52.     *dataStart = kInit;
  53.     *length = kInit;
  54.  
  55.     theSoundHeader = NewPtr (headerBytes);
  56.     theErr = MemError();
  57.     if (theSoundHeader != nil || theErr == noErr) {
  58.         /* This returns the number of the first resource of type 'snd ' */
  59.         theErr = MyGetFirstResource (theSoundInfo->refNum, 'snd ', &resNum);
  60.         if (theErr == noErr) {
  61.             theErr = MyGetResourcePosition (theSoundInfo->refNum, 'snd ', resNum, dataStart);
  62.             if (theErr == noErr) {
  63.                 theErr = FSRead (theSoundInfo->refNum, &headerBytes, theSoundHeader);
  64.                 if (theErr == noErr) {
  65.                     /* Could use SM 3.2's ParseSndHeader, but this is (supposed to be) educational */
  66.                     theErr = MyParseSndHeader (&(SndListResource*)theSoundHeader, &sndInfo, &numFrames, &dataOffset);
  67.                     if (theErr == noErr) {
  68.                         DisposePtr (theSoundHeader);                /* It's work is done */
  69.                         theErr = SetupDBHeader (theSoundInfo,
  70.                                                 sndInfo.sampleRate,
  71.                                                 sndInfo.sampleSize,
  72.                                                 sndInfo.numChannels,
  73.                                                 fixedCompression,    /* fixedCompression will work for uncompressed */
  74.                                                 sndInfo.format);    /* format is the really important field */
  75.                         theSoundInfo->needsMasking = false;            /* 'snd ' resources never need masking */
  76.                         *length = numFrames * theSoundInfo->doubleHeader.dbhPacketSize * sndInfo.numChannels;
  77.                         *dataStart += dataOffset;
  78.                     }
  79.                     else {
  80.                         DebugPrint ("\pParseSndHeader failed");
  81.                     }
  82.                 }
  83.                 else {
  84.                     DebugPrint ("\pFSRead failed");
  85.                 }
  86.             }
  87.             else {
  88.                 DebugPrint ("\pMyGetResourcePosition failed");
  89.             }
  90.         }
  91.         else {
  92.             DebugPrint ("\pMyGetFirstResource failed");
  93.         }
  94.     }
  95.     else {
  96.         DebugPrint ("\pNewPtr failed");
  97.     }
  98.  
  99.     if (theErr != noErr) {
  100.         DebugPrint ("\pError in ASoundGetSNDHeader");
  101.     }
  102.  
  103.     *length += *dataStart;    /* Otherwise we wouldn't read the last few bytes from the end of the sound. */
  104.  
  105.     return theErr;
  106. }
  107.  
  108. /*
  109.     This code parses a 'snd ' resource header.  While Sound Manager 3.2 will
  110.     do this for you, this is for education (and entertainment).  Just in case
  111.     the Sound Manager routine is better, try it first, if it's available.
  112. */
  113. /*-----------------------------------------------------------------------*/
  114.         OSErr    MyParseSndHeader        (SndListHandle theSoundHeader,
  115.                                         SoundComponentData *sndInfo,
  116.                                         unsigned long *numFrames,
  117.                                         unsigned long *dataOffset)
  118. /*-----------------------------------------------------------------------*/
  119. {
  120.     NumVersion                SndManagerVer;
  121.     headerTemplate            theHeader;
  122.     long                    headerOffset    = 0;
  123.     OSErr                    theErr            = noErr;
  124.     short                    numChannels        = 0,
  125.                             numCommands        = 0,
  126.                             i                = 0;
  127.     Boolean                    parsed            = false;
  128.     unsigned char            headerFormat    = 0;
  129.  
  130.     SndManagerVer = SndSoundManagerVersion ();
  131.  
  132.     /* If SM 3.2 is available, use its ParseSndHeader function */
  133.     if (SndManagerVer.majorRev >= 3 && SndManagerVer.minorAndBugRev >= 32) {
  134.         theErr = ParseSndHeader (theSoundHeader, sndInfo, numFrames, dataOffset);
  135.         parsed = true;
  136.     }
  137.  
  138.     /* If it's not available, or it failed, let's try it ourselves */
  139.     if (theErr != noErr || parsed == false) {
  140.         theErr = noErr;
  141.         switch ((*theSoundHeader)->format) {
  142.             case firstSoundFormat:                    /* Normal 'snd ' resource */
  143.                 if ((*theSoundHeader)->modifierPart->modNumber != kSampledSound) {
  144.                     theErr = badFormat;                /* can only deal with sampled-sound data */
  145.                 }
  146.                 else {
  147.                     numCommands = (*theSoundHeader)->numCommands;
  148.                     if (numCommands != 1) {
  149.                         theErr = badFormat;            /* can only deal with one sound per resource, for now */
  150.                     }
  151.                     else {
  152.                         for (i = 0; i < numCommands; i++) {
  153.                             if ((*theSoundHeader)->commandPart->cmd == kBufferCmd) {
  154.                                 headerOffset = (*theSoundHeader)->commandPart->param2;
  155.                             }
  156.                             else {
  157.                                 theErr = badFormat;    /* can only deal with sampled-sound data */
  158.                             }
  159.                         }
  160.                     }
  161.                 }
  162.                 break;
  163.             case secondSoundFormat:                    /* Hypercard 'snd ' resource */
  164.                 numCommands = ((Snd2ListPtr)(*theSoundHeader))->numCommands;
  165.                 if (numCommands != 1) {
  166.                     theErr = badFormat;                /* can only deal with one sound per resource, for now */
  167.                 }
  168.                 else {
  169.                     for (i = 0; i < numCommands; i++) {
  170.                         if (((Snd2ListPtr)(*theSoundHeader))->commandPart->cmd == kBufferCmd) {
  171.                             headerOffset = ((Snd2ListPtr)(*theSoundHeader))->commandPart->param2;
  172.                         }
  173.                         else {
  174.                             theErr = badFormat;        /* can only deal with sampled-sound data */
  175.                         }
  176.                     }
  177.                 }
  178.                 break;
  179.             default:
  180.                 theErr = badFormat;                    /* unknown resource format */
  181.         }
  182.         if (theErr == noErr) {
  183.             theHeader.standardHeaderPtr = (SoundHeaderPtr)((Ptr)(*theSoundHeader)+headerOffset);
  184.             switch (theHeader.standardHeaderPtr->encode) {
  185.                 case stdSH:
  186.                     theHeader.standardHeaderPtr = (SoundHeaderPtr)((Ptr)(*theSoundHeader)+headerOffset);
  187.                     sndInfo->format            = kOffsetBinary;    /* Can only be raw sounds */
  188.                     switch ((*theSoundHeader)->modifierPart->modInit & kChannelsMask) {
  189.                         case initMono:
  190.                             sndInfo->numChannels    = kMono;
  191.                             break;
  192.                         case initStereo:
  193.                             sndInfo->numChannels    = kStereo;
  194.                             break;
  195.                         default:
  196.                             theErr = badFormat;                    /* unknown number of channels */
  197.                     }
  198.                     sndInfo->sampleSize        = k8BitSample;        /* Can only be 8 bit sounds */
  199.                     sndInfo->sampleRate        = theHeader.standardHeaderPtr->sampleRate;
  200.                     sndInfo->sampleCount    = theHeader.standardHeaderPtr->length;
  201.                     *dataOffset                = headerOffset + sizeof (SoundHeader) - sizeof (short);
  202.                     break;
  203.                 case extSH:
  204.                     theHeader.extendedHeaderPtr = (ExtSoundHeaderPtr)((Ptr)(*theSoundHeader)+headerOffset);
  205.                     sndInfo->format            = kOffsetBinary;    /* Can only be raw sounds */
  206.                     sndInfo->numChannels    = theHeader.extendedHeaderPtr->numChannels;
  207.                     sndInfo->sampleSize        = theHeader.extendedHeaderPtr->sampleSize;
  208.                     sndInfo->sampleRate        = theHeader.extendedHeaderPtr->sampleRate;
  209.                     sndInfo->sampleCount    = theHeader.extendedHeaderPtr->numFrames;
  210.                     *dataOffset                = headerOffset + sizeof (ExtSoundHeader) - sizeof (short);
  211.                     break;
  212.                 case cmpSH:
  213.                     theHeader.compressedHeaderPtr = (CmpSoundHeaderPtr)((Ptr)(*theSoundHeader)+headerOffset);
  214.                     sndInfo->format            = theHeader.compressedHeaderPtr->format;
  215.                     if (sndInfo->format == 0) {
  216.                         switch (theHeader.compressedHeaderPtr->compressionID) {
  217.                             case twoToOne:
  218.                                 sndInfo->format     = kULawCompression;
  219.                                 break;
  220.                             case eightToThree:                    /* I don't know what compressor this is */
  221.                                 theErr = badFormat;
  222.                                 break;
  223.                             case threeToOne:
  224.                                 sndInfo->format     = kMACE3Compression;
  225.                                 break;
  226.                             case sixToOne:
  227.                                 sndInfo->format     = kMACE6Compression;
  228.                                 break;
  229.                             default:
  230.                                 DebugPrint ("\pUnknown sound format");
  231.                                 theErr = badFormat;
  232.                         }
  233.                     }
  234.                     sndInfo->numChannels    = theHeader.compressedHeaderPtr->numChannels;
  235.                     sndInfo->sampleSize        = theHeader.compressedHeaderPtr->sampleSize;
  236.                     sndInfo->sampleRate        = theHeader.compressedHeaderPtr->sampleRate;
  237.                     sndInfo->sampleCount    = theHeader.compressedHeaderPtr->numFrames;
  238.                     *dataOffset                = headerOffset + sizeof (CmpSoundHeader) - sizeof (short);
  239.                     break;
  240.                 default:
  241.                     theErr = badFormat;        /* A header format we don't know about */
  242.             }
  243.             *numFrames                = (unsigned long)sndInfo->sampleCount;
  244.             sndInfo->flags            = 0;    /* ?? */
  245.             sndInfo->buffer            = 0;    /* should always be 0, data follows header */
  246.             sndInfo->reserved        = 0;    /* just set it to 0 */
  247.         }
  248.  
  249.     }
  250.  
  251.     return theErr;
  252. }
  253.